import streamlit as st
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from datetime import datetime
import calendar


class ApexVisualization:
    def __init__(self):
        # 设置样式
        plt.style.use('dark_background')
        sns.set_palette("viridis")

        plt.rcParams['font.sans-serif'] = ['SimHei']  # 使用黑体
        plt.rcParams['axes.unicode_minus'] = False  # 正确显示负号

        # 生成模拟数据
        self.months = ['April', 'May', 'June', 'July', 'August']
        self.ranks = ['菜鸟', '青铜', '白银', '黄金', '铂金', '钻石', '大师', '猎杀', '职业', '挂']

        # 创建排名到数值的映射
        self.rank_mapping = {rank: i + 1 for i, rank in enumerate(self.ranks)}
        self.reverse_rank_mapping = {i + 1: rank for i, rank in enumerate(self.ranks)}

        # 创建模拟数据
        self.data = {}
        for i, month in enumerate(self.months):
            base_dist = np.random.normal(5.5, 2, 10000)
            base_dist = np.clip(base_dist, 1, 10)
            base_dist = np.round(base_dist).astype(int)

            counts = np.bincount(base_dist, minlength=12)[1:11]
            percentages = counts / counts.sum() * 100

            variation = np.random.uniform(0.9, 1.1, 10)
            percentages = percentages * variation
            percentages = percentages / percentages.sum() * 100

            self.data[month] = percentages

        # 转换为DataFrame
        self.df = pd.DataFrame(self.data, index=self.ranks)
        self.df.index.name = 'Rank'

    def plot_distribution(self, month):
        fig, ax = plt.subplots(figsize=(10, 6))

        if month in self.df.columns:
            data = self.df[month]
            bars = ax.bar(self.ranks, data, alpha=0.7, edgecolor='white')

            for i, v in enumerate(data):
                ax.text(i, v + 0.5, f'{v:.1f}%', ha='center', va='bottom', fontweight='bold')

            ax.set_title(f'Apex Legends 排名分布 - {month}', fontsize=16, fontweight='bold')
            ax.set_xlabel('排名', fontsize=12)
            ax.set_ylabel('玩家百分比 (%)', fontsize=12)
            ax.set_xticks(range(len(self.ranks)))
            ax.set_xticklabels(self.ranks)
            ax.grid(axis='y', alpha=0.3)
            ax.set_ylim(0, max(data) * 1.2)

            total_players = f"{np.random.randint(4000000, 5000000):,}".replace(",", " ")
            ax.text(0.02, 0.98, f'总玩家数: {total_players}',
                    transform=ax.transAxes, fontsize=10, verticalalignment='top',
                    bbox=dict(boxstyle='round', facecolor='grey', alpha=0.2))

            plt.tight_layout()
            return fig
        else:
            st.error(f"没有找到 {month} 的数据")
            return None

    def predict_future_months(self):

        # 训练数据
        X = []  # [月份数值, 排名数值]
        y = []  # 百分比

        month_mapping = {month: i + 1 for i, month in enumerate(self.months)}

        for month in self.months:
            month_num = month_mapping[month]
            for rank_num, rank_name in enumerate(self.ranks, 1):
                X.append([month_num, rank_num])
                y.append(self.df.loc[rank_name, month])

        X = np.array(X)
        y = np.array(y)

        # 特征
        poly = PolynomialFeatures(degree=2)
        X_poly = poly.fit_transform(X)

        # 训练模型
        model = LinearRegression()
        model.fit(X_poly, y)

        # 预测
        future_months = ['September', 'October']
        predictions = {}

        for i, month in enumerate(future_months, start=len(self.months) + 1):
            month_data = {}
            for rank_num in range(1, len(self.ranks) + 1):
                # 创建特征
                features = poly.transform([[i, rank_num]])
                # 预测
                prediction = model.predict(features)[0]
                prediction = max(0, min(100, prediction))
                month_data[self.reverse_rank_mapping[rank_num]] = prediction

            # 归一化
            total = sum(month_data.values())
            for rank in month_data:
                month_data[rank] = month_data[rank] / total * 100

            predictions[month] = month_data

        return predictions

    def plot_prediction(self, predictions, month):
        """绘制预测结果的图表"""
        if month not in predictions:
            st.error(f"没有找到 {month} 的预测数据")
            return None

        fig, ax = plt.subplots(figsize=(10, 6))

        data = predictions[month]
        values = [data[rank] for rank in self.ranks]

        bars = ax.bar(self.ranks, values, alpha=0.7, edgecolor='white', color='orange')

        for i, v in enumerate(values):
            ax.text(i, v + 0.5, f'{v:.1f}%', ha='center', va='bottom', fontweight='bold')

        ax.set_title(f'Apex Legends 排名分布预测 - {month}', fontsize=16, fontweight='bold')
        ax.set_xlabel('排名', fontsize=12)
        ax.set_ylabel('预测玩家百分比 (%)', fontsize=12)
        ax.set_xticks(range(len(self.ranks)))
        ax.set_xticklabels(self.ranks)
        ax.grid(axis='y', alpha=0.3)
        ax.set_ylim(0, max(values) * 1.2)

        ax.text(0.02, 0.98, '预测数据 (基于多项式回归模型)',
                transform=ax.transAxes, fontsize=10, verticalalignment='top',
                bbox=dict(boxstyle='round', facecolor='orange', alpha=0.2))

        plt.tight_layout()
        return fig



viz = ApexVisualization()


def show_apex_visualization():

    st.title("Apex Legends 排名分布分析")

    # 创建选项卡
    tab1, tab2, tab3 = st.tabs(["历史数据", "预测分析", "数据对比"])

    with tab1:
        st.header("历史排名分布")
        selected_month = st.selectbox("选择月份", viz.months, key="hist_month")

        if selected_month:
            fig = viz.plot_distribution(selected_month)
            if fig:
                st.pyplot(fig)
                st.subheader("详细数据")
                month_data = viz.df[selected_month].round(2)
                st.dataframe(month_data.rename("百分比 (%)"))

    with tab2:
        st.header("未来排名预测")
        st.info("使用机器学习模型（多项式回归）基于历史数据预测未来月份的排名分布")

        if st.button("生成预测", key="predict_btn"):
            with st.spinner("训练模型并生成预测..."):
                predictions = viz.predict_future_months()

                col1, col2 = st.columns(2)

                with col1:
                    st.subheader("9月预测")
                    fig_sep = viz.plot_prediction(predictions, "September")
                    if fig_sep:
                        st.pyplot(fig_sep)

                with col2:
                    st.subheader("10月预测")
                    fig_oct = viz.plot_prediction(predictions, "October")
                    if fig_oct:
                        st.pyplot(fig_oct)

                st.subheader("预测数据详情")
                pred_df = pd.DataFrame({
                    'Rank': viz.ranks,
                    'September': [predictions['September'][r] for r in viz.ranks],
                    'October': [predictions['October'][r] for r in viz.ranks]
                }).set_index('Rank').round(2)

                st.dataframe(pred_df)

    with tab3:
        st.header("月度数据对比")
        selected_months = st.multiselect(
            "选择要对比的月份",
            viz.months,
            default=[viz.months[0], viz.months[-1]],
            key="compare_months"
        )

        if len(selected_months) >= 2:
            compare_data = viz.df[selected_months]

            fig, ax = plt.subplots(figsize=(12, 6))
            x = np.arange(len(viz.ranks))
            width = 0.8 / len(selected_months)

            for i, month in enumerate(selected_months):
                offset = width * i - (width * (len(selected_months) - 1) / 2)
                ax.bar(x + offset, compare_data[month], width, label=month)

            ax.set_xlabel('排名')
            ax.set_ylabel('玩家百分比 (%)')
            ax.set_title('月度排名分布对比')
            ax.set_xticks(x)
            ax.set_xticklabels(viz.ranks)
            ax.legend()
            ax.grid(axis='y', alpha=0.3)

            plt.tight_layout()
            st.pyplot(fig)

            st.subheader("对比数据")
            st.dataframe(compare_data.round(2))
        else:
            st.warning("请至少选择两个月份进行对比")